Typically, when a computer program is written and compiled, there is no way to add functionality to the program without having to recompile the code. However, there are some techniques that enable a piece of software code to be added to the process of the executing program. For example, COMPEL is a software utility provided to execute arbitrary code in a context of a foreign process. COMPEL is part of CRIU (“Checkpoint/Restore In Userspace”), which is a software tool for the LINUX operating system provided to implement checkpoint/restore functionality for LINUX. Using COMPEL, a user creates a parasite code, compiles the code, and links the code using the COMPEL utility. Once compiled with COMPEL flags and linked, the parasite code can be executed in another process's context with the help of COMPEL library.
FIG. 1 illustrates a high-level flow diagram for execution and working with files of a conventional computer process. As shown, a process or task 10 that is executed by a computer processing unit of a computer access a file descriptor table 11 of the operating system of the computer to read data from and write data to a File “X”, denoted by reference 12. When the task 10 is to perform a read or write operation to the File X, the task 10 uses a system call and the descriptor (e.g., descriptor number 4), which provides a reference or indicator to the File X, is used as an argument. In other words, for any 1/O system call that operates on a file such as File X, the first argument for the system call is a file descriptor. Thus, in this instance, the process makes a system call for the 4th file descriptor in the file descriptor table 11 to write and read data to and from File X.
In this context, the COMPEL utility is able to add parasite code to the task 10 that can be executed in that process's context so that when it is executing its own code, the task 10 interrupts, executes the loaded code (i.e., the parasite code), and then continues to run the original compiled program code. COMPEL works by connecting to the process 10 using a debugging program interface of the operating system and stopping the process 10 as if it is interrupted at the breakpoint. For example, in LINUX, there is a debugging program interface that allows another process to connect to the process 10, and to read from and write to the memory of the process 10. In the process address space, COMPEL identifies a white space and writes the binary code (i.e., the parasite code) so that it is loaded into the process. Accordingly, using the debugging program interface, COMPEL changes the registers of the process 10 containing the next instruction (i.e., the “RIP”) to the entry point of the loaded binary code. Then, it gives the command to proceed execution of the process.
With the COMPEL utility, the binary code (i.e., the parasite code) is compiled in a way that when its execution comes to an end, it signals its stop point to the debugging programming interface. COMPEL intercepts that signal, unloads the binary code, and changes the process registers to the values that they had at the breakpoint, such that the process 10 proceeds to full execution. As a result, COMPEL facilitates the execution of a code fragment with the execution of process 10 without appearing to do so.
Although applications like the COMPEL utility enable code to be added to a compiled process (e.g., task 10), there is currently no ability to modify existing processes that perform operations for system resources after being compiled. For example, while the COMPEL utility can add code, it cannot modify an existing read and/or write operation from task 10 to File X. In other words, existing systems cannot access or modify the communication channel between task 10 and File X via file descriptor table 11. Accordingly, a more flexible approach is needed for easily modifying a complied computer program.